package socketmvc.server.tcp;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tio.core.ReadCompletionHandler;
import org.tio.core.ssl.SslUtils;
import org.tio.core.stat.IpStat;
import org.tio.server.*;
import org.tio.utils.SystemTimer;

import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;

public class TcpAcceptCompletionHandler extends AcceptCompletionHandler {
    private static Logger log = LoggerFactory.getLogger(TcpAcceptCompletionHandler.class);

    /**
     * @param asynchronousSocketChannel
     * @param tioServer
     * @author tanyaowu
     */
    @Override
    public void completed(AsynchronousSocketChannel asynchronousSocketChannel, TioServer tioServer) {
        try {
            TioServerConfig tioServerConfig = tioServer.getTioServerConfig();
            InetSocketAddress inetSocketAddress = (InetSocketAddress) asynchronousSocketChannel.getRemoteAddress();
            String clientIp = inetSocketAddress.getHostString();
            //			tioServerConfig.ips.get(clientIp).getRequestCount().incrementAndGet();

            //			CaffeineCache[] caches = tioServerConfig.ips.getCaches();
            //			for (CaffeineCache guavaCache : caches) {
            //				IpStat ipStat = (IpStat) guavaCache.get(clientIp);
            //				ipStat.getRequestCount().incrementAndGet();
            //			}

            if (org.tio.core.Tio.IpBlacklist.isInBlacklist(tioServerConfig, clientIp)) {
                log.info("{}在黑名单中, {}", clientIp, tioServerConfig.getName());
                asynchronousSocketChannel.close();
                return;
            }

            if (tioServerConfig.statOn) {
                ((ServerGroupStat) tioServerConfig.groupStat).accepted.incrementAndGet();
            }

            //			channelContext.getIpStat().getActivatedCount().incrementAndGet();
            //			for (CaffeineCache guavaCache : caches) {
            //				IpStat ipStat = (IpStat) guavaCache.get(clientIp);
            //				ipStat.getActivatedCount().incrementAndGet();
            //			}
            //			for (Long v : durationList) {
            //				IpStat ipStat = (IpStat) tioServerConfig.ips.get(v, clientIp);
            //				IpStat.getActivatedCount().incrementAndGet();
            //			}
            //			IpStat.getActivatedCount(clientIp, true).incrementAndGet();

            asynchronousSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
            asynchronousSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 64 * 1024);
            asynchronousSocketChannel.setOption(StandardSocketOptions.SO_SNDBUF, 64 * 1024);
            asynchronousSocketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);

            ServerChannelContext channelContext = new TcpServerChannelContext(tioServerConfig, asynchronousSocketChannel);
            channelContext.setClosed(false);
            channelContext.stat.setTimeFirstConnected(SystemTimer.currTime);
            channelContext.setServerNode(tioServer.getServerNode());

            //			channelContext.traceClient(ChannelAction.CONNECT, null, null);

            //			tioServerConfig.connecteds.add(channelContext);
            tioServerConfig.ips.bind(channelContext);

            boolean isConnected = true;
            boolean isReconnect = false;
            if (tioServerConfig.getTioServerListener() != null) {
                if (!SslUtils.isSsl(channelContext.tioConfig)) {
                    try {
                        tioServerConfig.getTioServerListener().onAfterConnected(channelContext, isConnected, isReconnect);
                    } catch (Throwable e) {
                        log.error(e.toString(), e);
                    }
                }
            }

            if (tioServerConfig.isIpStatEnable()) {
                try {
                    for (Long v : tioServerConfig.ipStats.durationList) {
                        IpStat ipStat = (IpStat) tioServerConfig.ipStats.get(v, channelContext);
                        ipStat.getRequestCount().incrementAndGet();
                        tioServerConfig.getIpStatListener().onAfterConnected(channelContext, isConnected, isReconnect, ipStat);
                    }
                } catch (Exception e) {
                    log.error(e.toString(), e);
                }
            }

            if (!tioServer.isWaitingStop()) {
                ReadCompletionHandler readCompletionHandler = channelContext.getReadCompletionHandler();
                ByteBuffer readByteBuffer = readCompletionHandler.getReadByteBuffer();//ByteBuffer.allocateDirect(channelContext.tioConfig.getReadBufferSize());
                readByteBuffer.position(0);
                readByteBuffer.limit(readByteBuffer.capacity());
                asynchronousSocketChannel.read(readByteBuffer, readByteBuffer, readCompletionHandler);
            }
        } catch (Throwable e) {
            log.error("", e);
        } finally {
            if (tioServer.isWaitingStop()) {
                log.info("{}即将关闭服务器，不再接受新请求", tioServer.getServerNode());
            } else {
                AsynchronousServerSocketChannel serverSocketChannel = tioServer.getServerSocketChannel();
                serverSocketChannel.accept(tioServer, this);
            }
        }
    }
}
